
/* GCSx
** WORLDPLAY.CPP
**
** World storage
** Gameplay members
*/

/*****************************************************************************
** Copyright (C) 2003-2006 Janson
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
*****************************************************************************/

#include "all.h"

WorldPlay::WorldPlay(const char* wFilename) throw_File : World(wFilename) { start_func
    currentScene = NULL;
    librariesLocked = allScriptsLocked = 0;
    // @TODO: ensure updated whenever saved game loading is implemented
    lastEntityId = 1;
    lastSpriteId = 1;
}

WorldPlay::~WorldPlay() { start_func
    while (librariesLocked) unlockLibraries();

    EntityIndex::iterator end = entitysById.end();
    for (EntityIndex::iterator pos = entitysById.begin(); pos != end; ++pos) {
        delete (*pos).second;
    }

    SpriteIndex::iterator end2 = spritesById.end();
    for (SpriteIndex::iterator pos2 = spritesById.begin(); pos2 != end2; ++pos2) {
        delete (*pos2).second;
    }
}

void WorldPlay::gameStart() throw_File { start_func
    int errs;
    if ( (errs = buildScripts()) ) {
        throw FileException("%d error(s) during script compilation- see debug console for details.", errs);
    }
    
    lockLibraries();

    if (startingScene)
        changeScene(findScene(startingScene));
    else
        changeScene(NULL);
}

void WorldPlay::changeScene(Scene* newScene) { start_func
    if (newScene != currentScene) {
        if (currentScene) currentScene->markUnlockPlay();
        currentScene = newScene;
        if (currentScene) {
            // @TODO: throw_File
            currentScene->markLockPlay();
            spawnScene(currentScene);
        }
    }
}

void WorldPlay::spawnScene(Scene* scene) { start_func
    if (scenesSpawned.find(scene->getId()) == scenesSpawned.end()) {
        // Spawn scene- first time loading
        scene->spawnScene();
        scenesSpawned.insert(scene->getId());
    }
}

void WorldPlay::draw() { start_func
    if (!currentScene) return;
    currentScene->draw();
}

void WorldPlay::indexEntity(Entity* addEntity) { start_func
    assert(addEntity);
    assert(entitysById.find(addEntity->getId()) == entitysById.end());

    entitysById.insert(pair<int, Entity*>(addEntity->getId(), addEntity));
}

void WorldPlay::deindexEntity(Entity* remEntity) { start_func
    assert(remEntity);
    entitysById.erase(remEntity->getId());
}

Entity* WorldPlay::findEntity(int fId) const { start_func
    EntityIndex::const_iterator loc = entitysById.find(fId);
    if (loc == entitysById.end()) return NULL;
    return (*loc).second;
}

int WorldPlay::unusedEntityId() { start_func
    while (entitysById.find(++lastEntityId) != entitysById.end()) ;
    return lastEntityId;
}

void WorldPlay::indexSprite(Sprite* addSprite) { start_func
    assert(addSprite);
    assert(spritesById.find(addSprite->getId()) == spritesById.end());

    spritesById.insert(pair<int, Sprite*>(addSprite->getId(), addSprite));
}

void WorldPlay::deindexSprite(Sprite* remSprite) { start_func
    assert(remSprite);
    spritesById.erase(remSprite->getId());
}

Sprite* WorldPlay::findSprite(int fId) const { start_func
    SpriteIndex::const_iterator loc = spritesById.find(fId);
    if (loc == spritesById.end()) return NULL;
    return (*loc).second;
}

int WorldPlay::unusedSpriteId() { start_func
    while (spritesById.find(++lastSpriteId) != spritesById.end()) ;
    return lastSpriteId;
}

void WorldPlay::cycle() { start_func
    if (currentScene) currentScene->cycle();
}

void WorldPlay::lockLibraries() { start_func
    if (!librariesLocked) {
        allScriptsLocked = config->readNum(LINKED_PREGENERATE);
        
        ScriptIndex::iterator pos;
        ScriptIndex::iterator end = scriptsById.end();
        for (pos = scriptsById.begin(); pos != end; ++pos) {
            assert(!(*pos).second->numErrors());
            if (((*pos).second->getType() == Script::SCRIPT_LIBRARY) ||
                (allScriptsLocked && ((*pos).second->getType() == Script::SCRIPT_CODE))) {
                (*pos).second->markLock();
                (*pos).second->link();
            }
        }
    }
    ++librariesLocked;
}

void WorldPlay::unlockLibraries() { start_func
    assert(librariesLocked);
    --librariesLocked;;
    if (librariesLocked == 0) {
        ScriptIndex::iterator pos;
        ScriptIndex::iterator end = scriptsById.end();
        for (pos = scriptsById.begin(); pos != end; ++pos) {
            if (((*pos).second->getType() == Script::SCRIPT_LIBRARY) ||
                (allScriptsLocked && ((*pos).second->getType() == Script::SCRIPT_CODE)))
                (*pos).second->markUnlock();
        }
    }
}
